package com.example.mybatis.session;
import com.example.mybatis.binding.MapperRegistry;
import com.example.mybatis.datasource.druid.DruidDataSourceFactory;
import com.example.mybatis.datasource.pooled.PooledDataSourceFactory;
import com.example.mybatis.datasource.unpooled.UnpooledDataSourceFactory;
import com.example.mybatis.excutor.Executor;
import com.example.mybatis.excutor.SimpleExecutor;
import com.example.mybatis.excutor.resultSet.DefaultResultSetHandler;
import com.example.mybatis.excutor.resultSet.ResultSetHandler;
import com.example.mybatis.excutor.statement.PreparedStatementHandler;
import com.example.mybatis.excutor.statement.StatementHandler;
import com.example.mybatis.mapping.BoundSql;
import com.example.mybatis.mapping.Environment;
import com.example.mybatis.mapping.MappedStatement;
import com.example.mybatis.scripting.LanguageDriverRegistry;
import com.example.mybatis.transaction.Transaction;
import com.example.mybatis.transaction.jdbc.JdbcTransactionFactory;
import com.example.mybatis.type.TypeAliasRegistry;
import lombok.Data;
import org.apache.ibatis.scripting.xmltags.XMLLanguageDriver;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

@Data
public class Configuration {

    /**
     *
     * 环境配置
     * */
    private Environment environment;



    /**
     * 映射注册机
     */
    protected MapperRegistry mapperRegistry = new MapperRegistry(this);

    /**
     * 映射的语句，存在Map里
     */
    protected final Map<String, MappedStatement> mappedStatements = new HashMap<>();


    /**
     * 注册基础类型注册器
     * */
    protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();

    /**
     * 保存加载过的资源，防止重复加载
     *
     * */
    protected final Set<String> loadedResources = new HashSet<>();


    protected final LanguageDriverRegistry languageRegistry = new LanguageDriverRegistry();



    public Configuration() {
        typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
        typeAliasRegistry.registerAlias("DRUID", DruidDataSourceFactory.class);
        typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);
        typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
        languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);


    }


    public void addMappers(String packageName) {
        mapperRegistry.addMappers(packageName);
    }

    public <T> void addMapper(Class<T> type) {
        mapperRegistry.addMapper(type);
    }

    public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        return mapperRegistry.getMapper(type, sqlSession);
    }

    public boolean hasMapper(Class<?> type) {
        return mapperRegistry.hasMapper(type);
    }

    public void addMappedStatement(MappedStatement ms) {
        mappedStatements.put(ms.getId(), ms);
    }

    public MappedStatement getMappedStatement(String id) {
        return mappedStatements.get(id);
    }

    public Environment getEnvironment() {
        return environment;
    }

    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    /**
     * 创建结果集处理器
     */
    public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, BoundSql boundSql) {
        return new DefaultResultSetHandler(executor, mappedStatement, boundSql);
    }

    /**
     * 生产执行器
     */
    public Executor newExecutor(Transaction transaction) {
        return new SimpleExecutor(this, transaction);
    }

    /**
     * 创建语句处理器
     */
    public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, ResultHandler resultHandler, BoundSql boundSql) {
        return new PreparedStatementHandler(executor, mappedStatement, parameter, resultHandler, boundSql);
    }


    /**
     * 判断是否属于已经加载过的资源
     * */
    public boolean isResourceLoaded(String resource) {
        return loadedResources.contains(resource);
    }

    /**
     * 往容器中添加，表示该资源已经是加载过了
     * */
    public void addLoadedResource(String resource) {
        loadedResources.add(resource);
    }


    public LanguageDriverRegistry getLanguageRegistry() {
        return languageRegistry;
    }


}
